package com.meiyuetao.myt.purchase.service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

import lab.s2jh.auth.entity.Department;
import lab.s2jh.auth.security.AuthUserHolder;
import lab.s2jh.auth.service.DepartmentService;
import lab.s2jh.bpm.service.ActivitiService;
import lab.s2jh.core.dao.BaseDao;
import lab.s2jh.core.service.BaseService;
import lab.s2jh.core.service.Validation;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.google.common.collect.Lists;
import com.meiyuetao.myt.core.constant.VoucherStateEnum;
import com.meiyuetao.myt.core.constant.VoucherTypeEnum;
import com.meiyuetao.myt.core.service.VoucherNumGenerateService;
import com.meiyuetao.myt.finance.dao.BizTradeUnitDao;
import com.meiyuetao.myt.finance.entity.AccountInOut;
import com.meiyuetao.myt.finance.entity.BizTradeUnit;
import com.meiyuetao.myt.finance.entity.TradeReceipt;
import com.meiyuetao.myt.finance.entity.TradeReceiptDetail;
import com.meiyuetao.myt.finance.service.AccountInOutService;
import com.meiyuetao.myt.finance.service.TradeReceiptService;
import com.meiyuetao.myt.md.dao.CommodityDao;
import com.meiyuetao.myt.md.entity.Commodity;
import com.meiyuetao.myt.purchase.dao.PurchaseReturnOrderDao;
import com.meiyuetao.myt.purchase.entity.PurchaseReturnOrder;
import com.meiyuetao.myt.purchase.entity.PurchaseReturnOrderDetail;
import com.meiyuetao.myt.purchase.entity.Supplier;
import com.meiyuetao.myt.stock.dao.StorageLocationDao;
import com.meiyuetao.myt.stock.entity.CommodityStock;
import com.meiyuetao.myt.stock.entity.StockInOut;
import com.meiyuetao.myt.stock.entity.StorageLocation;
import com.meiyuetao.myt.stock.service.CommodityStockService;
import com.meiyuetao.myt.stock.service.StockInOutService;

@Service
@Transactional
public class PurchaseReturnOrderService extends BaseService<PurchaseReturnOrder, Long> {

    @Autowired
    private PurchaseReturnOrderDao purchaseReturnOrderDao;
    @Autowired(required = false)
    private ActivitiService activitiService;
    @Autowired
    private VoucherNumGenerateService voucherNumGenerateService;
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private BizTradeUnitDao bizTradeUnitDao;
    @Autowired
    private TradeReceiptService tradeReceiptService;
    @Autowired
    private AccountInOutService accountInOutService;
    @Autowired
    private CommodityDao commodityDao;
    @Autowired
    private StockInOutService stockInOutService;
    @Autowired
    private StorageLocationDao storageLocationDao;
    @Autowired
    private CommodityStockService commodityStockService;

    @Override
    protected BaseDao<PurchaseReturnOrder, Long> getEntityDao() {
        return purchaseReturnOrderDao;
    }

    public void bpmCreate(PurchaseReturnOrder entity, Map<String, Object> variables) {
        this.save(entity);
        activitiService.startProcessInstanceByKey("BPM_PURCHASE_RETURN_ORDER", entity);
    }

    public void bpmUpdate(PurchaseReturnOrder entity, String taskId, Map<String, Object> variables) {
        this.save(entity);
        activitiService.completeTask(taskId, variables);
    }

    @Override
    public void delete(PurchaseReturnOrder entity) {
        activitiService.deleteProcessInstanceByEntity(entity);
        super.delete(entity);
    }

    public void bpmLevel1Audit(PurchaseReturnOrder entity, String taskId, Map<String, Object> variables) {
        this.bpmUpdate(entity, taskId, variables);
    }

    public void bpmCreateReceivablesReceipt(PurchaseReturnOrder entity, String taskId, List<TradeReceiptDetail> tradeReceiptDetails) {
        Supplier supplier = entity.getSupplier();
        // 创建付款单
        TradeReceipt tradeReceipt = new TradeReceipt();
        tradeReceipt.setVoucher(voucherNumGenerateService.getVoucherNumByType(VoucherTypeEnum.SKD));
        tradeReceipt.setVoucherDate(new Date());
        tradeReceipt.setVoucherUser(AuthUserHolder.getLogonUser());
        Department department = AuthUserHolder.getLogonUser().getDepartment();
        if (department == null) {
            department = departmentService.findByProperty("code", "MGMT");
        }
        tradeReceipt.setVoucherDepartment(department);
        BizTradeUnit bizTradeUnit = bizTradeUnitDao.findOne(supplier.getBizTradeUnitId());
        tradeReceipt.setBizTradeUnit(bizTradeUnit);
        tradeReceipt.setBizVoucher(entity.getVoucher());
        tradeReceipt.setBizVoucherType(VoucherTypeEnum.CGTH);// 采购退货单
        tradeReceipt.setReferenceVoucher(entity.getVoucher());
        tradeReceipt.setReceiptType(VoucherTypeEnum.SKD);
        tradeReceipt.setPayTime(new Date());
        tradeReceipt.setVoucherState(VoucherStateEnum.POST);
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (TradeReceiptDetail tradeReceiptDetail : tradeReceiptDetails) {
            tradeReceiptDetail.setTradeReceipt(tradeReceipt);
            tradeReceiptDetail.setPayTime(new Date());
            totalAmount = totalAmount.add(tradeReceiptDetail.getAmount());
            tradeReceipt.addTradeReceiptDetail(tradeReceiptDetail);
        }
        tradeReceipt.setTotalAmount(totalAmount);
        tradeReceipt.setAccountSubject(entity.getAccountSubject());

        tradeReceiptService.create(tradeReceipt);

        // this.bpmUpdate(entity, taskId, null);
    }

    /**
     * 记账
     * 
     * @param entity
     */
    public void handleAccountInOut(PurchaseReturnOrder entity) {
        // 记账
        List<AccountInOut> accountInOuts = Lists.newArrayList();

        // 贷： 应收账款
        AccountInOut accountInOut = buildDefaultAccountInOut(entity);
        accountInOut.setAccountSubjectCode("1122");
        accountInOut.setAccountSummary("采购退货应收账款");
        BigDecimal amount = entity.getAmount();// 应收金额 应是折后价格
        accountInOut.setAmount(amount);
        Supplier supplier = entity.getSupplier();
        accountInOut.setBizTradeUnit(bizTradeUnitDao.findOne(supplier.getBizTradeUnitId()));
        accountInOut.setAccountDirection(false);
        accountInOuts.add(accountInOut);

        // 借：1406=库存商品
        AccountInOut accountInOut2 = buildDefaultAccountInOut(entity);
        accountInOut2.setAccountSubjectCode("1406");
        accountInOut2.setAccountSummary("采购退货库存商品");
        accountInOut2.setAmount(entity.getAmount());
        accountInOut2.setAccountDirection(true);
        accountInOuts.add(accountInOut2);

        // 运费记账
        BigDecimal logisticsAmount = entity.getTotalDeliveryAmount();
        if (logisticsAmount != null && logisticsAmount.floatValue() != 0) {
            Validation.notNull(entity.getLogistics(), "有运费金额必须有对应快递公司");

            // 贷：2202=应付账款
            AccountInOut accountInOut3 = buildDefaultAccountInOut(entity);
            Supplier logistics = entity.getLogistics();
            accountInOut3.setBizTradeUnit(bizTradeUnitDao.findOne(logistics.getBizTradeUnitId()));
            accountInOut3.setAccountSubjectCode("2202");
            accountInOut3.setAccountSummary("采购单退货快递费");
            accountInOut3.setAmount(logisticsAmount);
            accountInOut3.setAccountDirection(false);
            accountInOuts.add(accountInOut3);

            // 借：6601=销售费用
            AccountInOut accountInOut4 = buildDefaultAccountInOut(entity);
            accountInOut4.setAccountSubjectCode("6601");
            accountInOut4.setAmount(logisticsAmount);
            accountInOut4.setAccountSummary("采购单退货快递费");
            accountInOut4.setAccountDirection(true);
            accountInOuts.add(accountInOut4);
        }

        accountInOutService.saveBalance(accountInOuts);
    }

    private AccountInOut buildDefaultAccountInOut(PurchaseReturnOrder entity) {
        AccountInOut accountInOut = new AccountInOut();
        accountInOut.setVoucher(entity.getVoucher());
        accountInOut.setVoucherType(VoucherTypeEnum.CGTH);
        accountInOut.setPostingDate(entity.getVoucherDate());
        return accountInOut;
    }

    public void handleStockQuantity(PurchaseReturnOrder bindingEntity) {
        for (PurchaseReturnOrderDetail prod : bindingEntity.getPurchaseReturnOrderDetails()) {
            StockInOut stockInOut = buildDefaultStockInOut(bindingEntity, prod);
            stockInOut.setDiffQuantity(prod.getQuantity().negate());
            CommodityStock commodityStock = findCommodityCommodityStock(prod);
            stockInOut.setDiffStockAmount(commodityStock.getCostPrice().multiply(prod.getQuantity().negate()));
            stockInOut.setOperationSummary("采购退货扣减库存量");
            stockInOutService.saveCascade(stockInOut);
        }

    }

    private CommodityStock findCommodityCommodityStock(PurchaseReturnOrderDetail prod) {

        Commodity commodity = commodityDao.findOne(prod.getCommodity().getId());
        StorageLocation storageLocation = storageLocationDao.findOne(prod.getStorageLocation().getId());
        String batchNo = prod.getBatchNo();
        CommodityStock commodityStock = commodityStockService.findBy(commodity, storageLocation, batchNo);
        Validation.isTrue(commodityStock != null, "须先初始化维护库存数据: 商品=[" + commodity.getDisplay() + "],库存地=[" + storageLocation.getDisplay() + "],批次号=[" + batchNo + "]");
        /*
         * Validation.isTrue(commodityStock.getCostPrice() != null &&
         * commodityStock.getCostPrice().doubleValue() > 0, "成本价格无效: 商品=[" +
         * commodity.getDisplay() + "],库存地=[" + storageLocation.getDisplay() +
         * "],批次号=[" + batchNo + "],成本价=[" + commodityStock.getCostPrice() +
         * "]");
         */
        return commodityStock;
    }

    private StockInOut buildDefaultStockInOut(PurchaseReturnOrder purchaseReturnOrder, PurchaseReturnOrderDetail prod) {
        CommodityStock commodityStock = findCommodityCommodityStock(prod);
        StockInOut stockInOut = new StockInOut(purchaseReturnOrder.getVoucher(), prod.getSubVoucher(), VoucherTypeEnum.CGTH, commodityStock);
        return stockInOut;
    }

    public void redword(PurchaseReturnOrder entity) {
        Assert.isTrue(entity.getRedwordDate() == null);

        // 移除工作流实例
        activitiService.deleteProcessInstanceByEntity(entity);

        entity.setRedwordDate(new Date());
        entity.setLastOperationSummary(entity.buildLastOperationSummary("红冲"));
        purchaseReturnOrderDao.save(entity);

        // 克隆创建红冲对象，只复制主对象，明细行项数据不复制
        PurchaseReturnOrder redwordTarget = new PurchaseReturnOrder();
        String[] copyIgnoreProperties = ArrayUtils.addAll(entity.retriveCommonProperties(), new String[] { "purchaseReturnOrderDetails", "voucher", "voucherDate" });
        BeanUtils.copyProperties(entity, redwordTarget, copyIgnoreProperties);
        redwordTarget.setVoucherDate(new Date());
        redwordTarget.setVoucher("R" + entity.getVoucher());
        purchaseReturnOrderDao.save(redwordTarget);

        // 处理库存红冲退回
        // stockInOutService.redword(entity.getVoucher(), VoucherTypeEnum.CGTH,
        // redwordTarget.getVoucher());

        // 处理财务红冲退回
        // accountInOutService.redword(entity.getVoucher(),
        // VoucherTypeEnum.CGTH, redwordTarget.getVoucher());
    }

}
